//
// Created by 李传智 on 2018/4/12.
//

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavcodec/jni.h>
}

#include "FFDecode.h"
#include "Logger.h"

void FFDecode::initHard(void *vm) {
    av_jni_set_java_vm(vm, 0);
}

bool FFDecode::open(CodecParameter codecParameter, bool isHard) {
    close();
    AVCodecParameters *parameters = codecParameter.parameters;
    if (!parameters) {
        return false;
    }
    AVCodec *codec;
    int ret = 0;

    // 1. 查找解码器
    codec = avcodec_find_decoder(parameters->codec_id);
    if (isHard) {
        codec = avcodec_find_decoder_by_name("h264_mediacodec");
    }
    if (!codec) {
        LOG_E("avcodec_find_decoder failed");
        return false;
    }
    LOG_I("avcodec_find_decoder success, isHard is %d", isHard);

    // 2. 创建解码器上下文并复制参数
    mutex.lock();
    this->codecContext = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(this->codecContext, parameters);
    this->codecContext->thread_count = 8;

    // 3. 打开解码器
    ret = avcodec_open2(this->codecContext, codec, 0);
    if (ret != 0) {
        char buf[1024] = {0};
        av_strerror(ret, buf, sizeof(buf) - 1);
        LOG_E("avcodec_open2 failed, error = %d", ret);
        mutex.unlock();
        return false;
    }

    codecType = codecContext->codec_type;
    isAudio = codecType == AVMEDIA_TYPE_AUDIO;

    mutex.unlock();

    return true;
}

void FFDecode::close() {
    IDecode::clear();
    mutex.lock();
    pts = 0;
    if (frame) {
        av_frame_free(&frame);
    }
    if (codecContext) {
        avcodec_close(codecContext);
        avcodec_free_context(&codecContext);
    }
    mutex.unlock();
}

bool FFDecode::sendPacket(VideoData pkt) {
    if (pkt.size == 0 || !pkt.data) {
        return false;
    }
    mutex.lock();
    if (!codecContext) {
        mutex.unlock();
        return false;
    }
    int ret = avcodec_send_packet(codecContext, (AVPacket *) pkt.data);
    mutex.unlock();
    return ret == 0;
}

VideoData FFDecode::receiveFrame() {
    VideoData data;
    mutex.lock();
    if (!codecContext) {
        mutex.unlock();
        return data;
    }
    if (!frame) {
        frame = av_frame_alloc();
    }
    int ret = 0;
    ret = avcodec_receive_frame(codecContext, frame);
    if (ret != 0) {
        mutex.unlock();
        return data;
    }
    if (codecType == AVMEDIA_TYPE_VIDEO) {
        int lineSize =
                this->frame->linesize[0] + this->frame->linesize[1] + this->frame->linesize[2];
        data.size = lineSize * this->frame->height;
        data.width = this->frame->width;
        data.height = this->frame->height;
    } else if (codecType == AVMEDIA_TYPE_AUDIO) {
        // 每个样本的字节数（16位=2个字节）* 每个通道的样本数 * 通道数
        data.size = (av_get_bytes_per_sample((AVSampleFormat) frame->format) * frame->nb_samples *
                     frame->channels);
        data.nbSamples = this->frame->nb_samples;
    }
    data.format = this->frame->format;
    memcpy(data.src, frame->data, sizeof(data.src));
    data.pts = frame->pts;
    mutex.unlock();
    return data;
}

void FFDecode::clear() {
    IDecode::clear();
    mutex.lock();
    if(codecContext) {
        avcodec_flush_buffers(codecContext);
    }
    mutex.unlock();
}